import { _decorator, Component, Node, UITransform, Vec2 } from 'cc';
const { ccclass, property } = _decorator;

class OBB {
    centre: Vec2;
    halfSize: Vec2;
    axes: Vec2[];

    constructor(centre: Vec2, halfSize: Vec2, angle: number) {
        this.centre = centre;
        this.halfSize = halfSize;

        this.axes = [
            new Vec2(Math.cos(angle), Math.sin(angle)),
            new Vec2(-Math.sin(angle), Math.cos(angle))
        ]
    }
}

@ccclass('obb')
export class obb extends Component {

    @property(Node)
    private object1: Node = null;

    @property(Node)
    private object2: Node = null;

    private obb1: OBB = null;
    private obb2: OBB = null;

    createObb(temp: Node): OBB{
        let pos = new Vec2(temp.position.x, temp.position.y);
        let rota = (temp.angle * Math.PI) / 180;
        let boxSize = temp.getComponent(UITransform).contentSize;
        let halfSize = new Vec2(boxSize.width/2, boxSize.height/2);

        return new OBB(pos, halfSize, rota);
    }

    start() {
        this.obb1 = this.createObb(this.object1);
        this.obb2 = this.createObb(this.object2);
    }

    minMax(obb: OBB, axis: Vec2): [number, number] {
        let centre = new Vec2(obb.centre);
        let axes = [];
        for (let i = 0; i < obb.axes.length; i++) {
            axes.push(new Vec2(obb.axes[i]));
        }
        let halfSize = new Vec2(obb.halfSize);

        let xShift = new Vec2(axes[0].multiplyScalar(halfSize.x));
        let yShift = new Vec2(axes[1].multiplyScalar(halfSize.y));

        let p1 = new Vec2(centre.add(xShift).add(yShift));
        centre = new Vec2(obb.centre);
        let p2 = new Vec2(centre.add(xShift).subtract(yShift));
        centre = new Vec2(obb.centre);
        let p3 = new Vec2(centre.subtract(xShift).subtract(yShift));
        centre = new Vec2(obb.centre);
        let p4 = new Vec2(centre.subtract(xShift).add(yShift));
        centre = new Vec2(obb.centre);

        let points = [ p1, p2, p3, p4 ];

        let min = Vec2.dot(axis, points[0]);
        let max = min;
        for (let i = 1; i < points.length; i++) {
            const projection = Vec2.dot(axis, points[i]);
            if (projection < min) min = projection;
            if (projection > max) max = projection;
        }
        points = [];
        return [min, max];
    }

    isOverlap(obb1: OBB, obb2:OBB, axis: Vec2) {
        const [min1, max1] = this.minMax(obb1, axis);
        const [min2, max2] = this.minMax(obb2, axis);

        return !(min1 > max2 || min2 > max1);
    }

    checkOBBCollision(obb1: OBB, obb2: OBB): boolean {
        const axes = [
            obb1.axes[0], obb1.axes[1],
            obb2.axes[0], obb2.axes[1]
        ];

        for (const axis of axes) {
            if (!this.isOverlap(obb1, obb2, axis)) {
                return false;
            }
        }
        return true;
    }

    update(deltaTime: number) {
        this.obb1 = this.createObb(this.object1);
        this.obb2 = this.createObb(this.object2);
        console.log(this.checkOBBCollision(this.obb1, this.obb2));
    }
}
